use codegraph_core::{Parser, LanguageAdapter};
use codegraph_parser::TreeSitterParser;
use codegraph_languages::PythonAdapter;

#[tokio::test]
async fn test_python_semantic_extraction() {
    let adapter = PythonAdapter::new();
    let parser = TreeSitterParser::python().expect("Failed to create Python parser");
    
    let python_code = r#"
import os
import sys
from typing import List, Dict

def fibonacci(n: int) -> int:
    """Calculate the nth Fibonacci number."""
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

class Calculator:
    def __init__(self):
        self.history = []
    
    def add(self, a: float, b: float) -> float:
        result = a + b
        self.history.append(f"{a} + {b} = {result}")
        return result
    
    def multiply(self, a: float, b: float) -> float:
        result = a * b
        self.history.append(f"{a} * {b} = {result}")
        return result

class ScientificCalculator(Calculator):
    def __init__(self):
        super().__init__()
        self.pi = 3.14159
    
    def power(self, base: float, exponent: float) -> float:
        result = base ** exponent
        self.history.append(f"{base} ^ {exponent} = {result}")
        return result

# Usage
calc = ScientificCalculator()
result = calc.add(fibonacci(5), fibonacci(6))
power_result = calc.power(2, 8)
print(f"Results: {result}, {power_result}")
"#;

    // Parse the code
    let tree = parser.parse(python_code, None).await.expect("Failed to parse Python code");
    
    // Extract nodes
    let nodes = adapter.extract_nodes(tree.as_ref()).await.expect("Failed to extract nodes");
    
    // Verify we extracted some nodes
    assert!(!nodes.is_empty(), "Should extract at least some nodes");
    
    // Check that we have different types of nodes
    let mut has_function = false;
    let mut has_class = false;
    let mut has_variable = false;
    let mut has_import = false;
    
    for node in &nodes {
        match node.node_type() {
            codegraph_core::NodeType::Function => has_function = true,
            codegraph_core::NodeType::Class => has_class = true,
            codegraph_core::NodeType::Variable => has_variable = true,
            codegraph_core::NodeType::Import => has_import = true,
            _ => {}
        }
    }
    
    // Our simple implementation should detect at least some patterns
    assert!(has_function || has_class || has_variable || has_import, 
            "Should extract at least one type of semantic node");
    
    println!("Extracted {} nodes:", nodes.len());
    for node in &nodes {
        println!("  - {} ({}): {}",
                 ToStringHelper::to_string(node.node_type()),
                 node.language(),
                 node.name());
    }
    
    // Extract edges
    let node_refs: Vec<&dyn codegraph_core::CodeNode> = nodes.iter().map(|n| n.as_ref()).collect();
    let edges = adapter.extract_edges(tree.as_ref(), &node_refs).await.expect("Failed to extract edges");
    
    println!("Extracted {} edges:", edges.len());
    for edge in &edges {
        println!("  - {} -> {} ({})", 
                 edge.source(), 
                 edge.target(), 
                 edge.edge_type().to_string());
    }
}

#[tokio::test]
async fn test_language_adapter_interface() {
    let adapter = PythonAdapter::new();
    
    // Test basic properties
    assert_eq!(adapter.language_id(), "python");
    assert!(adapter.file_extensions().contains(&".py".to_string()));
    assert!(adapter.file_extensions().contains(&".pyw".to_string()));
    
    // Test parser creation
    let parser = adapter.create_parser().await.expect("Failed to create parser");
    assert_eq!(parser.language_id(), "python");
    
    // Test syntax type mapping
    assert_eq!(adapter.map_syntax_type_to_node_type("function_definition"), 
               codegraph_core::NodeType::Function);
    assert_eq!(adapter.map_syntax_type_to_node_type("class_definition"), 
               codegraph_core::NodeType::Class);
    assert_eq!(adapter.map_syntax_type_to_node_type("assignment"), 
               codegraph_core::NodeType::Variable);
    assert_eq!(adapter.map_syntax_type_to_node_type("import_statement"), 
               codegraph_core::NodeType::Import);
}

// Helper trait to convert NodeType and EdgeType to string for display
trait ToStringHelper {
    fn to_string(&self) -> String;
}

impl ToStringHelper for codegraph_core::NodeType {
    fn to_string(&self) -> String {
        match self {
            codegraph_core::NodeType::Function => "Function".to_string(),
            codegraph_core::NodeType::Class => "Class".to_string(),
            codegraph_core::NodeType::Variable => "Variable".to_string(),
            codegraph_core::NodeType::Import => "Import".to_string(),
            codegraph_core::NodeType::Call => "Call".to_string(),
            codegraph_core::NodeType::Reference => "Reference".to_string(),
            _ => "Other".to_string(),
        }
    }
}

impl ToStringHelper for codegraph_core::EdgeType {
    fn to_string(&self) -> String {
        match self {
            codegraph_core::EdgeType::Calls => "Calls".to_string(),
            codegraph_core::EdgeType::Inherits => "Inherits".to_string(),
            codegraph_core::EdgeType::References => "References".to_string(),
            codegraph_core::EdgeType::Imports => "Imports".to_string(),
            codegraph_core::EdgeType::Defines => "Defines".to_string(),
            _ => "Other".to_string(),
        }
    }
}
